module utils.mover3;

import utils.matrix;
import utils.vector3;

public struct Mover3(T) {
    public alias Vector3!(T) MVector;

    public MVector pos, dir, up;

    public static Mover3 opCall(MVector pos, MVector dir, MVector up) {
        Mover3 ret;
        ret.pos = pos;
        ret.dir = dir;
        ret.up = up;
        return ret;
    }

    public MVector side() {
        return (dir | up).normal();
    }

    public void updateDir(MVector newDir) {
        dir = newDir.normal();
        auto normal = Vector3f(0, -1, 0) | dir;
        up = (normal | dir).normal();
    }

    public void lookAt(MVector point, MVector newUp) {
        dir = (point - pos).normal();
        up = newUp.normal();
    }

    public void lookAtFrom(MVector newPos, MVector point) {
        pos = newPos;
        updateDir(point - pos);
    }

    public void lookAt(MVector point) {
        updateDir(point - pos);
    }

    public void moveRelative(MVector moveRel) {
        MVector moveVec;
        moveVec = up*moveRel.y;
        moveVec += side()*moveRel.x;
        moveVec += dir*moveRel.z;
        pos = pos + moveVec;
    }

    public void rotateRelative(MVector rel) {
        Matrix3!(T) m = void;
        Matrix3!(T) src = Matrix3!(T)(side(), up, dir);
        m = Matrix3!(T).fromAngles(rel);
        src *= m;
        up = src.m[1].normal();
        dir = src.m[2].normal();
    }

    public void moveAbsolute(MVector moveVec) {
        pos = pos + moveVec;
    }
}

public alias Mover3!(float) Mover3f;
